#include "lrtsp_server.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "rtsp_client.h"
#include "rtsp_clients_manager.h"
#include "lrtsp_stream.h"

#define BACKLOG 32

struct lrtsp_server{
	char* host;
	char* port;
	int listen_fd;

	int running;
};

static struct lrtsp_server *S = NULL;

int _lrtsp_server_main_loop_run(void)
{
	fd_set fdset;
	fd_set err_fdset;
	struct timeval tv = {0};
	int mfd = 0;
	int ret = -1;
	int client_fd = -1;
	struct sockaddr_in client_address = {0};
	int client_len = 0;
	struct RtspClient* rtsp_client = NULL;
	int i = 0;

	while(S->running){
		FD_ZERO(&fdset);
		FD_ZERO(&err_fdset);
		/*if is listen fd add the fd to  client*/
		FD_SET(S->listen_fd, &fdset);
		FD_SET(S->listen_fd, &err_fdset);
		mfd = 0;
		mfd = (S->listen_fd > mfd)?S->listen_fd:mfd;

		for(i = 0; i < rtsp_clients_manager_get_count(); i++){
			rtsp_client = rtsp_clients_manager_get(i);
			if((client_fd = rtsp_client_get_fd(rtsp_client)) >= 0){
				FD_SET(client_fd, &fdset);
				FD_SET(client_fd, &err_fdset);
				mfd = (client_fd > mfd)?client_fd:mfd;
			}
		}

		tv.tv_sec = 0;
		tv.tv_usec = 5000*1000;
		ret = select(mfd + 1, &fdset, NULL, &err_fdset, &tv);
		if(ret != 0){
			if(ret > 0){
				/*ckeck   rtsp client*/
				for(i = 0; i < rtsp_clients_manager_get_count();){
					rtsp_client = rtsp_clients_manager_get(i);
					client_fd = rtsp_client_get_fd(rtsp_client);
					if(client_fd > 0 && FD_ISSET(client_fd, &fdset)){
						/*dispatch*/
						if(rtsp_client_dispatch(rtsp_client) != 0){
						    printf("remove the rtsp client!\n");
							rtsp_clients_manager_remove(rtsp_client);
						}
						else{
							i++;
						}
					}
					else if(FD_ISSET(client_fd, &err_fdset)){
						rtsp_clients_manager_remove(rtsp_client);
						printf("Debug: remove cliend rtsp client fd(%d)\n", client_fd);
						continue;
					}
					else{
					    printf("jump out!\n");
                        i++;
					    continue;
					}
				}
				if(FD_ISSET(S->listen_fd, &fdset)){
					client_len = sizeof(client_address);
					client_fd= accept(S->listen_fd, (struct sockaddr *)&client_address, (socklen_t*)&client_len);
					printf("Debug:get a accept! client fd(%d)\n", client_fd);
					rtsp_client = rtsp_client_create(client_fd);
					rtsp_clients_manager_add(rtsp_client);	
				}
				if(FD_ISSET(S->listen_fd, &err_fdset)){
				    printf("listen socket fd get a error1\n");
				}
			}
		}
	}

	return 0;
}

int lrtsp_server_init(const char* host, const char* port)
{
	if(S != NULL){
		printf("lrtsp server is inited\n");
		return -1;
	}

	S = malloc(sizeof(*S));
	if(S == NULL){
		printf("lrtsp malloc memory failed!\n");
		return -1;
	}

	S->host = strdup(host); 
	S->port = strdup(port);

	rtsp_clients_manager_init(64);
	lrtsp_stream_manager_init();

	return 0;
}


int lrtsp_server_run()
{
	int listen_fd = -1;
    int reuse=1;
    struct sockaddr_in server_address;
    int server_len;
	
	listen_fd =  socket(AF_INET, SOCK_STREAM, 0);
    (void) setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse,sizeof(reuse));
	
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(atoi(S->port));
    server_len = sizeof(server_address); 
   	if(bind(listen_fd, (struct sockaddr *)&server_address, server_len) == -1){
   		perror("bind port failed!\n");
		close(listen_fd);
		return -1;
	}
    if(listen(listen_fd, BACKLOG) == -1){
    	perror("listen failed!\n");
		close(listen_fd);
		return -1;
	}

	S->listen_fd = listen_fd;
	S->running = 1;
	
	_lrtsp_server_main_loop_run();

	return 0;
}

int lrtsp_server_deinit()
{
    S->running = 0;

    rtsp_clients_manager_deinit();
	lrtsp_stream_manager_deinit();

	return 0;
}